package com.gome.ss.core.plugin;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;
import org.jdom2.JDOMException;

import com.gome.ss.common.AppConfiguer;
import com.gome.ss.common.Utils;
import com.gome.ss.core.datapipe.DataPipeInterface;
import com.gome.ss.core.download.SpiderDataMap;
import com.gome.ss.core.download.SpiderRequestInterface;
import com.gome.ss.core.download.SpiderResponseInterface;
import com.gome.ss.core.download.StartRequest;
import com.gome.ss.core.schedule.ScheduleManager;

public class SpiderPluginHandle implements SpiderPluginInteface {
	private static Logger logger = Logger.getLogger(SpiderPluginHandle.class);
	
	protected PluginClassLoader pluginClassLoader;
	protected Class<?> pluginClazz = null;
	protected Object pluginObject = null;

	protected String pluginFileName = "";
	protected String pluginName = "";
	protected String pluginQualified = "";
	protected boolean processable = false;
	private String startRequestMethod = "";
	private String pluginDesc = "";
	private boolean isStarted = false;
	private boolean isProcessing = false;
	
	private List<StartRequest> startReqs = new ArrayList<StartRequest>();
	
	public SpiderPluginHandle() {
		URL[] urls = new URL[] {};
		pluginClassLoader = new PluginClassLoader(urls, ClassLoader.getSystemClassLoader());
	}
	
	public void start(boolean incremental) {
		isProcessing = true;
		isStarted = false;
		
		if (!incremental) {
			List<Plugin> plugins = PluginManager.getInstance().getPlugin(pluginName);
			if (plugins.get(0).isLocalPlugin()) {
				for (Plugin plugin : plugins) {
					plugin.getHandle().onStart();
				}
			} else {
				onStart();
			}
		} else {
			List<Plugin> plugins = PluginManager.getInstance().getPlugin(pluginName);
			if (plugins.get(0).isLocalPlugin()) {
				for (Plugin plugin : plugins) {
					plugin.getHandle().onStartWithIncrementalMode();
				}
			} else {
				onStartWithIncrementalMode();
			}
		}
	}
	
	public void setStarted() {
		isStarted = true;
	}
	
	public boolean getStarted() {
		return isStarted;
	}
	
	public void stop() {
		isProcessing = false;
		onStop();
		isStarted = false;
	}

	public void loadClazz(String pluginFileName, String pluginName, String pluginQualified,  boolean processable) throws ClassNotFoundException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException, IOException, InstantiationException, JDOMException {
       
		this.pluginFileName = pluginFileName;
		this.pluginName = pluginName;
		this.pluginQualified = pluginQualified;
		this.processable = processable;
        
		String pluginPath = AppConfiguer.getPluginDir() + pluginFileName;

        this.pluginClazz = this.pluginClassLoader.loadJar(new File(pluginPath).toURI().toURL(), pluginQualified);
        this.pluginObject = this.pluginClazz.newInstance();
	}

	public boolean processable() {
		return processable;
	}

	public String getPluginFileName() {
		return pluginFileName;
	}

	public String getPluginName() {
		return pluginName;
	}

	public String getPluginQualified() {
		return pluginQualified;
	}
	
	public String getPluginQualifiedName() {
		return pluginQualified;
	}

	public synchronized void addStartReq(String link, String groupName, int retryCount, String qualifiedString) {
		StartRequest req = new StartRequest();
		req.link = link;
		req.groupName = groupName;
		req.retryCount = retryCount;
		req.qualified = qualifiedString == null ? "" : qualifiedString;
		this.startReqs.add(req);
	}
	
	public synchronized void setStartReq(List<StartRequest> links) {
		this.startReqs.clear();
		this.startReqs.addAll(links);
	}
	
	public List<StartRequest> getStartReqs() {
		return this.startReqs;
	}

	@Override
	public boolean init(){
		// TODO Auto-generated method stub
        Method method;
		try {
			method = pluginClazz.getDeclaredMethod("init");
			Boolean ret = (Boolean) method.invoke(pluginObject, null);
			return ret;
		} catch (Exception e) {
			logger.error(Utils.getTrace(e));
			return false;
		}
	}

	@Override
	public void setConfig(Object config) {
		// TODO Auto-generated method stub

        Method method;
		try {
			method = pluginClazz.getDeclaredMethod("setConfig", Object.class);
			Boolean ret = (Boolean) method.invoke(pluginObject, config);
		} catch (Exception e) {
			logger.error(Utils.getTrace(e));
		}
	}

	@Override
	public boolean beforDownLoad(SpiderRequestInterface request) throws Exception{
		// TODO Auto-generated method stub

        Method method = pluginClazz.getDeclaredMethod("beforDownLoad", SpiderRequestInterface.class);
		Boolean ret = (Boolean) method.invoke(pluginObject, request);
		return ret;
	}

	@Override
	public void onStart() {
		// TODO Auto-generated method stub
        Method method;
        
		try {
			method = pluginClazz.getDeclaredMethod("onStart");
			method.invoke(pluginObject, null);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			logger.error(Utils.getTrace(e));
		}
	}

	@Override
	public void onStop() {
		// TODO Auto-generated method stub
        Method method;
        
		try {
			method = pluginClazz.getDeclaredMethod("onStop");
			method.invoke(pluginObject, null);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			logger.error(Utils.getTrace(e));
		}
	}

	@Override
	public void onDownLoadFinished(SpiderResponseInterface response) throws Exception{
		// TODO Auto-generated method stub

        Method method = pluginClazz.getDeclaredMethod("onDownLoadFinished", SpiderResponseInterface.class);
		method.invoke(pluginObject, response);
	}

	@Override
	public List<SpiderRequestInterface> parseLink(
			SpiderResponseInterface response) throws Exception {
		// TODO Auto-generated method stub

        Method method = pluginClazz.getDeclaredMethod("parseLink", SpiderResponseInterface.class);
		List<SpiderRequestInterface> ret = (List<SpiderRequestInterface>) method.invoke(pluginObject, response);
		return ret;
	}

	@Override
	public SpiderDataMap parseData(SpiderResponseInterface response) throws Exception {
		// TODO Auto-generated method stub

        Method method = pluginClazz.getDeclaredMethod("parseData", SpiderResponseInterface.class);
		SpiderDataMap ret = (SpiderDataMap) method.invoke(pluginObject, response);
		return ret;
	}

	@Override
	public DataPipeInterface datePipe() throws Exception{
		// TODO Auto-generated method stub
        Method method = pluginClazz.getDeclaredMethod("datePipe");
		DataPipeInterface ret = (DataPipeInterface) method.invoke(pluginObject, null);
		return ret;
	}

	@Override
	public List<StartRequest> getStartRequest(){
		// TODO Auto-generated method stub

        Method method;
		try {
			method = pluginClazz.getDeclaredMethod("getStartRequest");
			List<StartRequest> ret = (List<StartRequest>) method.invoke(pluginObject, null);
			return ret;
		} catch (Exception e) {
			// TODO Auto-generated catch block
			logger.error(Utils.getTrace(e));
			return new ArrayList<StartRequest>();
		}
	}

    public String getStartRequestMethod() {
		return startRequestMethod;
	}

	public void setStartRequestMethod(String startRequestMethod) {
		this.startRequestMethod = startRequestMethod;
	}
	
	public String getPluginDesc() {
		return pluginDesc;
	}

	public void setPluginDesc(String pluginDesc) {
		this.pluginDesc = pluginDesc;
	}

	public boolean isProcessing() {
		return isProcessing;
	}

	public void setProcessing(boolean isProcessing) {
		this.isProcessing = isProcessing;
	}

	static class PluginClassLoader  extends URLClassLoader {
		
        public PluginClassLoader(URL[] urls) {
			super(urls);
			// TODO Auto-generated constructor stub
		}
        
        public PluginClassLoader(URL[] urls, ClassLoader parent) {
			super(urls, parent);
			// TODO Auto-generated constructor stub
		}
        
		public Class<?> loadJar(URL jarUrl, String classQualified) {
			// TODO Auto-generated method stub
			super.addURL(jarUrl);
			try {
				Class<?> objClass = this.loadClass(classQualified);
				return objClass;
			} catch (ClassNotFoundException e) {
				// TODO Auto-generated catch block
				logger.error(Utils.getTrace(e));
			}
			return null;
		}
    }

	@Override
	public void destory(){
        Method method;
		try {
			method = pluginClazz.getDeclaredMethod("destory");
			method.invoke(pluginObject, null);
		} catch (Exception e) {
			logger.error(Utils.getTrace(e));
		}
	}

	@Override
	public boolean onStartWithIncrementalMode() {
		// TODO Auto-generated method stub

        Method method;
        
		try {
			method = pluginClazz.getDeclaredMethod("onStartWithIncrementalMode");
			Boolean ret = (Boolean) method.invoke(pluginObject, null);
			return ret;
		} catch (Exception e) {
			// TODO Auto-generated catch block
			logger.error(Utils.getTrace(e));
			return false;
		}
	}
	
}
